﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using BussinessLogic.Exercise;
using BussinessLogic.Services;
using BussinessLogic.Models;
using Newtonsoft.Json;
using System.IO;
using System.Security.Cryptography;
using BussinessLogic.Helpers;
using BussinessLogic;

namespace AspMVCProject.Controllers
{
    [Authorize]
    public class ExerciseController : Controller
    {
        public ActionResult Index()
        {
            if (!AccountService.IsUserInRole(User.Identity.Name, AccountService.UserRole.Administrator))
            {
                return RedirectToAction("LogOn", "Account");
            }

            List<ExerciseListItemModel> exercises = StudyServices.GetAllActivities();

            return View(exercises);
        }

        public ActionResult Create()
        {
            CreateExercise exercise = new CreateExercise();

            exercise.ExerciseTypes = new List<ExerciseType>();
            foreach (var item in Enum.GetValues(typeof(ActivityType)))
            {
                exercise.ExerciseTypes.Add(new ExerciseType
                {
                    ID = (int)item,
                    Name = item.ToString()
                });
            };

            return View(exercise);
        }

        [HttpPost]
        public ActionResult Create(CreateExercise model)
        {
            int exerciseId = StudyServices.CreateActivity(model);

            switch (model.ExerciseType)
            {
                case (int)ActivityType.Questionnaire:
                    return RedirectToAction("Questionnaire", new { id = exerciseId });
                case (int)ActivityType.Exercise:
                    return RedirectToAction("CreateExercise", new { id = exerciseId });
                case (int)ActivityType.MatrixExercise:
                    return RedirectToAction("CreateMatrixExercise", new { id = exerciseId });
                default:
                    break;
            }

            return View();
        }

        public ActionResult Edit(int id)
        {
            CreateExercise exercise = StudyServices.GetExercise(id);

            exercise.ExerciseTypes = new List<ExerciseType>();
            foreach (var item in Enum.GetValues(typeof(ActivityType)))
            {
                exercise.ExerciseTypes.Add(new ExerciseType
                {
                    ID = (int)item,
                    Name = item.ToString()
                });
            };

            return View(exercise);
        }

        [HttpPost]
        public ActionResult Edit(CreateExercise model, int id)
        {
            int exerciseId = StudyServices.CreateActivity(model);

            return RedirectToAction("Index");
        }

        public ActionResult Delete(int id)
        {
            StudyServices.DeleteActivity(id);

            return RedirectToAction("Index");
        }

        public ActionResult Questionnaire(int id)
        {
            QuestionnaireMaintenance qmaint = StudyServices.GetQuestionnaire(id);

            if (qmaint == null)
            {
                qmaint = new QuestionnaireMaintenance();
                Question q1 = new Question { Text = "New Question", HasFreeAnswer = true, HasMultipleChoice = false };

                qmaint.Questions = new List<Question> { q1 };

            }

            return View(qmaint);
        }

        [HttpPost]
        public ActionResult Questionnaire(string jsonResult)
        {
            QuestionnaireMaintenance protocol = JsonConvert.DeserializeObject<QuestionnaireMaintenance>(jsonResult);

            StudyServices.SaveQuestionnaire(protocol);

            return RedirectToAction("Index");
        }

        public ActionResult DailyQuestionnaire()
        {
            QuestionnaireDaily qd = new QuestionnaireDaily { Name = "Fist Questionnaire", Description = "Description for Questionnaire" };

            DailyQuestion q1 = new DailyQuestion { ID = 1, Text = "What is your overall satisfaction rating with our company?", Position = 1, HasFreeAnswer = false, HasMultipleChoice = false };
            q1.Answers = new List<DailyAnswer> 
            { 
                new DailyAnswer { ID = 1, Position = 1, Text = "Very Satisfied"},
                new DailyAnswer { ID = 2, Position = 2, Text = "Somewhat Satisfied"},
                new DailyAnswer { ID = 3, Position = 3, Text = "Neither Satisfied Nor Dissatisfied"},
                new DailyAnswer { ID = 4, Position = 4, Text = "Somewhat Dissatisfied"},
                new DailyAnswer { ID = 5, Position = 5, Text = "Very Dissatisfied"}
            };

            DailyQuestion q2 = new DailyQuestion { ID = 2, Text = "Please tell us why you feel that way.", Position = 3, HasFreeAnswer = true, HasMultipleChoice = false };

            DailyQuestion q3 = new DailyQuestion { ID = 3, Text = "How likely are you to recommend our product to a friend or colleague?", Position = 3, HasFreeAnswer = false, HasMultipleChoice = true };
            q3.Answers = new List<DailyAnswer> 
            { 
                new DailyAnswer { ID = 6, Position = 1, Text = "Very Likely"},
                new DailyAnswer { ID = 7, Position = 2, Text = "Somewhat Likely"},
                new DailyAnswer { ID = 8, Position = 3, Text = "Neither Likely Nor Unlikely"},
                new DailyAnswer { ID = 9, Position = 4, Text = "Somewhat Unlikely"},
                new DailyAnswer { ID = 10, Position = 5, Text = "Very Unlikely"}
            };

            qd.Questions = new List<DailyQuestion> { q1, q2, q3 };

            return View(qd);
        }

        [HttpPost]
        public ActionResult DailyQuestionnaire(string jsonResult)
        {
            QuestionnaireResult protocol = JsonConvert.DeserializeObject<QuestionnaireResult>(jsonResult);
            return RedirectToAction("Questionnaire");
        }

        public ActionResult UploadPictures()
        {
            return View();
        }

        [HttpPost]
        public ActionResult UploadPictures(IEnumerable<HttpPostedFileBase> neutral, IEnumerable<HttpPostedFileBase> negative)
        {
            foreach (var neutralPhoto in neutral)
            {
                if (neutralPhoto.ContentLength > 0)
                {
                    var fileName = Path.GetFileName(neutralPhoto.FileName);
                    var path = Path.Combine(Server.MapPath("~/uploads/neutral"), fileName);
                    neutralPhoto.SaveAs(path);
                }
            }

            foreach (var negativePhoto in negative)
            {
                if (negativePhoto.ContentLength > 0)
                {
                    var fileName = Path.GetFileName(negativePhoto.FileName);
                    var path = Path.Combine(Server.MapPath("~/uploads/negative"), fileName);
                    negativePhoto.SaveAs(path);
                }
            }

            return View();
        }

        public ActionResult SelectPictures(int id)
        {
            SelectPicture ec = new SelectPicture();
            ec.ID = id;

            ec.NeutralPhotos = new List<string>();
            ec.NegativePhotos = new List<string>();

            string[] negativePaths = Directory.GetFiles(Server.MapPath("~/uploads/negative"));
            foreach (var negative in negativePaths)
            {
                ec.NegativePhotos.Add(Path.GetFileName(negative));
            }

            string[] neutralPaths = Directory.GetFiles(Server.MapPath("~/uploads/neutral"));
            foreach (var neutral in neutralPaths)
            {
                ec.NeutralPhotos.Add(Path.GetFileName(neutral));
            }


            return View(ec);
        }

        [HttpPost]
        public ActionResult SelectPictures(List<string> neutrals, List<string> negatives, int id)
        {
            ExerciseMaintain em = new ExerciseMaintain();

            em.NeutralPhotos = new List<string>();
            em.NegativePhotos = new List<string>();

            string[] negativePaths = Directory.GetFiles(Server.MapPath("~/uploads/negative"));
            foreach (var negative in negativePaths)
            {
                em.NegativePhotos.Add(Path.GetFileName(negative));
            }

            string[] neutralPaths = Directory.GetFiles(Server.MapPath("~/uploads/neutral"));
            foreach (var neutral in neutralPaths)
            {
                em.NeutralPhotos.Add(Path.GetFileName(neutral));
            }

            em.Trials = new List<ExerciseTrial>();

            foreach (ExerciseTrial.Position neutralPosition in Enum.GetValues(typeof(ExerciseTrial.Position)))
            {
                foreach (ExerciseTrial.Position letterPosition in Enum.GetValues(typeof(ExerciseTrial.Position)))
                {
                    foreach (ExerciseTrial.LetterType letter in Enum.GetValues(typeof(ExerciseTrial.LetterType)))
                    {
                        em.Trials.Add(new ExerciseTrial { Letter = letter, LetterPosition = letterPosition, NeutralPosition = neutralPosition });
                    }
                }
            }

            return View("CreateExercise", em);
        }

        public ActionResult CreateMatrixExercise(int id)
        {
            MatrixExerciseMaintain em = StudyServices.GetMatrixExerciseProtocol(id);

            if (em == null)
            {
                em = new MatrixExerciseMaintain();
            }
            em.NeutralPhotos = new List<string>();
            em.NegativePhotos = new List<string>();

            string[] negativePaths = Directory.GetFiles(Server.MapPath("~/uploads/negative"));
            foreach (var negative in negativePaths)
            {
                em.NegativePhotos.Add(Path.GetFileName(negative));
            }


            string[] neutralPaths = Directory.GetFiles(Server.MapPath("~/uploads/neutral"));
            foreach (var neutral in neutralPaths)
            {
                em.NeutralPhotos.Add(Path.GetFileName(neutral));
            }



            return View(em);
        }

        [HttpPost]
        public ActionResult CreateMatrixExercise(MatrixExerciseMaintain em)
        {
            if (em.NegativePhotos == null || em.NeutralPhotos == null)
            {
                em.NeutralPhotos = new List<string>();
                em.NegativePhotos = new List<string>();
                string[] negativePaths = Directory.GetFiles(Server.MapPath("~/uploads/negative"));
                foreach (var negative in negativePaths)
                {
                    em.NegativePhotos.Add(Path.GetFileName(negative));
                }


                string[] neutralPaths = Directory.GetFiles(Server.MapPath("~/uploads/neutral"));
                foreach (var neutral in neutralPaths)
                {
                    em.NeutralPhotos.Add(Path.GetFileName(neutral));
                }

                ModelState.AddModelError("", "One or more photos must be selected");
                return View(em);
            }

            StudyServices.SaveMatrixExercise(em);

            return RedirectToAction("Index");
        }

        public ActionResult CreateExercise(int id)
        {
            ExerciseMaintain em = StudyServices.GetExerciseProtocol(id);

            if (em == null)
            {
                em = new ExerciseMaintain();
            }
            em.NeutralPhotos = new List<string>();
            em.NegativePhotos = new List<string>();

            string[] negativePaths = Directory.GetFiles(Server.MapPath("~/uploads/negative"));
            foreach (var negative in negativePaths)
            {
                em.NegativePhotos.Add(Path.GetFileName(negative));
            }


            string[] neutralPaths = Directory.GetFiles(Server.MapPath("~/uploads/neutral"));
            foreach (var neutral in neutralPaths)
            {
                em.NeutralPhotos.Add(Path.GetFileName(neutral));
            }

            em.Trials = new List<ExerciseTrial>();

            int i = 0;
            foreach (ExerciseTrial.Position neutralPosition in Enum.GetValues(typeof(ExerciseTrial.Position)))
            {
                foreach (ExerciseTrial.Position letterPosition in Enum.GetValues(typeof(ExerciseTrial.Position)))
                {
                    foreach (ExerciseTrial.LetterType letter in Enum.GetValues(typeof(ExerciseTrial.LetterType)))
                    {
                        var trial = new ExerciseTrial { ID = i++, Letter = letter, LetterPosition = letterPosition, NeutralPosition = neutralPosition };
                        if (em.SavedTrials != null)
                        {
                            foreach (var st in em.SavedTrials)
                            {
                                if (trial.Letter == st.Letter && trial.LetterPosition == st.LetterPosition && trial.NeutralPosition == st.NeutralPosition)
                                {
                                    trial.Checked = true;
                                    trial.Repeat = st.Repeat;
                                }
                            }
                        }
                        em.Trials.Add(trial);
                    }
                }
            }

            foreach (var t in em.Trials)
            {
                if (t.Repeat == 0)
                {
                    t.Repeat = 1;
                }
            }

            return View(em);
        }

        [HttpPost]
        public ActionResult CreateExercise(ExerciseMaintain em)
        {
            if (em.NegativePhotos == null || em.NeutralPhotos == null || em.NegativePhotos.Count != em.NeutralPhotos.Count)
            {
                em.NeutralPhotos = new List<string>();
                em.NegativePhotos = new List<string>();
                string[] negativePaths = Directory.GetFiles(Server.MapPath("~/uploads/negative"));
                foreach (var negative in negativePaths)
                {
                    em.NegativePhotos.Add(Path.GetFileName(negative));
                }


                string[] neutralPaths = Directory.GetFiles(Server.MapPath("~/uploads/neutral"));
                foreach (var neutral in neutralPaths)
                {
                    em.NeutralPhotos.Add(Path.GetFileName(neutral));
                }

                em.Trials = new List<ExerciseTrial>();

                int i = 0;
                foreach (ExerciseTrial.Position neutralPosition in Enum.GetValues(typeof(ExerciseTrial.Position)))
                {
                    foreach (ExerciseTrial.Position letterPosition in Enum.GetValues(typeof(ExerciseTrial.Position)))
                    {
                        foreach (ExerciseTrial.LetterType letter in Enum.GetValues(typeof(ExerciseTrial.LetterType)))
                        {
                            var trial = new ExerciseTrial { ID = i++, Letter = letter, LetterPosition = letterPosition, NeutralPosition = neutralPosition };
                            if (em.SavedTrials != null)
                            {
                                foreach (var st in em.SavedTrials)
                                {
                                    if (trial.Letter == st.Letter && trial.LetterPosition == st.LetterPosition && trial.NeutralPosition == st.NeutralPosition)
                                    {
                                        trial.Checked = true;
                                    }
                                }
                            }
                            em.Trials.Add(trial);
                        }
                    }
                }
                if (em.NegativePhotos.Count != em.NeutralPhotos.Count)
                {
                    ModelState.AddModelError("", "Neutral and negative number of photos must match");
                }
                else
                {
                    ModelState.AddModelError("", "One or more photos must be selected");
                }
                return View(em);
            }

            var trials = new List<ExerciseTrial>();
            foreach (ExerciseTrial.Position neutralPosition in Enum.GetValues(typeof(ExerciseTrial.Position)))
            {
                foreach (ExerciseTrial.Position letterPosition in Enum.GetValues(typeof(ExerciseTrial.Position)))
                {
                    foreach (ExerciseTrial.LetterType letter in Enum.GetValues(typeof(ExerciseTrial.LetterType)))
                    {
                        trials.Add(new ExerciseTrial { Letter = letter, LetterPosition = letterPosition, NeutralPosition = neutralPosition });
                    }
                }
            }
            em.Trials = new List<ExerciseTrial>();
            if (em.CheckedTrials != null)
            {
                foreach (var trial in em.CheckedTrials)
                {
                    trials[trial].Repeat = em.CheckedTrialsRepeat[trial];
                    em.Trials.Add(trials[trial]);
                }
            }

            StudyServices.SaveExercise(em);


            return RedirectToAction("Index");
        }

        public ActionResult ExerciseSession()
        {
            ExerciseProtocol protocol = new ExerciseProtocol();
            protocol.PictureTime = 200;
            protocol.CrossNumberTime = 320;
            protocol.FixationTrial = 2;
            protocol.AcomodationTrials = 2;
            protocol.FinalSession = false;
            protocol.Trials = new List<ExerciseTrial>();

            List<string> neutrals = new List<string> { "n1.png", "n2.png" };
            List<string> negatives = new List<string> { "neg1.png", "neg2.png" };

            List<ExerciseTrial> trainingTrials = new List<ExerciseTrial>();
            trainingTrials.Add(new ExerciseTrial { Letter = ExerciseTrial.LetterType.E, LetterPosition = ExerciseTrial.Position.Up, NeutralPosition = ExerciseTrial.Position.Up });
            trainingTrials.Add(new ExerciseTrial { Letter = ExerciseTrial.LetterType.F, LetterPosition = ExerciseTrial.Position.Down, NeutralPosition = ExerciseTrial.Position.Up });
            trainingTrials.Add(new ExerciseTrial { Letter = ExerciseTrial.LetterType.F, LetterPosition = ExerciseTrial.Position.Down, NeutralPosition = ExerciseTrial.Position.Down });


            List<ExerciseTrial> allCombinations = new List<ExerciseTrial>();

            foreach (var neutralPhoto in neutrals)
            {
                foreach (var negativePhoto in negatives)
                {
                    foreach (ExerciseTrial.Position neutralPosition in Enum.GetValues(typeof(ExerciseTrial.Position)))
                    {
                        foreach (ExerciseTrial.Position letterPosition in Enum.GetValues(typeof(ExerciseTrial.Position)))
                        {
                            foreach (ExerciseTrial.LetterType letter in Enum.GetValues(typeof(ExerciseTrial.LetterType)))
                            {
                                allCombinations.Add(new ExerciseTrial { NeutralPhoto = neutralPhoto, NegativePhoto = negativePhoto, Letter = letter, LetterPosition = letterPosition, NeutralPosition = neutralPosition });
                            }
                        }
                    }
                }
            }

            foreach (var neutralPhoto in neutrals)
            {
                foreach (var neutralPhoto2 in neutrals)
                {
                    foreach (ExerciseTrial.Position letterPosition in Enum.GetValues(typeof(ExerciseTrial.Position)))
                    {
                        foreach (ExerciseTrial.LetterType letter in Enum.GetValues(typeof(ExerciseTrial.LetterType)))
                        {
                            allCombinations.Add(new ExerciseTrial { NegativeNeutral = true, NeutralPhoto = neutralPhoto, NegativePhoto = neutralPhoto2, Letter = letter, LetterPosition = letterPosition, NeutralPosition = ExerciseTrial.Position.Up });
                        }
                    }
                }
            }

            //allCombinations.Shuffle();
            allCombinations = allCombinations.OrderBy(a => Guid.NewGuid()).ToList();

            Random randomGenerator = new Random();

            for (int i = 0; i < protocol.AcomodationTrials; i++)
            {
                // add acomodation
                int index = randomGenerator.Next(allCombinations.Count);
                var selectedTrial = allCombinations[index].Clone();
                selectedTrial.SType = ExerciseTrial.SequenceType.Acomodation;
                protocol.Trials.Add(selectedTrial);
            }

            // add baseline
            // basline will not be cloned !
            allCombinations.ForEach((t) => { t.SType = ExerciseTrial.SequenceType.Baseline; protocol.Trials.Add(t); });

            //add photos for training
            foreach (var trial in trainingTrials)
            {
                int iNeutral = randomGenerator.Next(neutrals.Count);
                int iNegative = randomGenerator.Next(negatives.Count);

                trial.NeutralPhoto = neutrals[iNeutral];
                trial.NegativePhoto = negatives[iNegative];
                trial.SType = ExerciseTrial.SequenceType.Training;
            }
            trainingTrials.ForEach(t => protocol.Trials.Add(t));

            //final session
            if (protocol.FinalSession)
            {
                //allCombinations.Shuffle();
                allCombinations = allCombinations.OrderBy(a => Guid.NewGuid()).ToList();
                foreach (var trial in allCombinations)
                {
                    var fTrial = trial.Clone();
                    fTrial.SType = ExerciseTrial.SequenceType.Final;
                    protocol.Trials.Add(fTrial);
                }
            }

            //fixation trials

            for (int i = 0; i < protocol.FixationTrial; i++)
            {
                int position = randomGenerator.Next(protocol.AcomodationTrials, protocol.Trials.Count);
                var trial = new ExerciseTrial
                {
                    SType = ExerciseTrial.SequenceType.Fixation,
                    Digit = randomGenerator.Next(1, 4)
                };

                protocol.Trials.Insert(position, trial);
            }


            return View(protocol);
        }

        [HttpPost]
        public ActionResult ExerciseSession(string jsonResult)
        {
            List<ExerciseTrial> trials = JsonConvert.DeserializeObject<List<ExerciseTrial>>(jsonResult);
            return RedirectToAction("ExerciseSession");
        }


    }
}
